// effect中的所有属性 都会收集effect track
// 当这个属性发生变化 会重新执行effect trigger
export function effect(fn, options = {}) {
    const effect = createReactiveEffect(fn, options)

    if (!options.lazy) { //默认的effect会执行,依赖的数据变化也会执行
        effect()
    }
    return effect
}

let uid = 0
let acctiveEffect //存储当前effect
let effectStack = [] //保证effect顺序的正确性
function createReactiveEffect(fn, options) {
    const effect = function reactiveEffect() {
      // 去重
    //   不然会出现死循环的情况
       if (!effectStack.includes(effect)) {
        try{
            effectStack.push(effect)
            acctiveEffect = effect
            console.log('effect')
            return fn()
            
           }finally{
            effectStack.pop(effect)
            acctiveEffect = effectStack[effectStack.length - 1]
           }
       }
    }
    effect.id = uid++
    effect._isEffect = true
    effect.raw = fn
    effect.options = options
    return effect
}

const targetMap = new WeakMap()
export function track(target, type, key) {
    // console.log(target, key, acctiveEffect)
    console.log(targetMap)
    if (acctiveEffect === undefined) {
        return
    }
    let depsMap = targetMap.get(target)
    if (!depsMap) {
        targetMap.set(target, (depsMap = new Map))
    }
    let dep = depsMap.get(key)
    if (!dep) {
        depsMap.set(key, (dep = new Set))
    }
    if (!dep.has(acctiveEffect)) {
        dep.add(acctiveEffect)
    }
    // console.log(targetMap)
}

/**
    weakmap
    key: {name: '展示', age: 40, list: Array(3)}
    value: Map(2) {'name' => Set(1), 'age' => Set(1)}
 */

// 找属性对应的effect，让其执行（数组、对象）
export function trigger (target, type, key, newValue, oldValue) {
    console.log(target, type, key, newValue, oldValue)

    // 获取收集的依赖
    const depsMap = targetMap.get(target)
    // console.log(depsMap)
    if (!depsMap) {
        return
    }

    // 去重effect依赖
    // 避免重复执行
    const effects = new Set()
    const add = (dep) => {
        if (dep) {
            dep.forEach((effect) => effects.add(effect))
        }
    }

    // 修改数组的长度，影响比较大
    if (key === 'length' && Array.isArray(target)) {
        // 对应的长度有依赖收集，需要更新
        depsMap.forEach((dep, key, arr) => {
            // console.log(typeof key)
            // console.log(dep, key, arr, '@@')
            // 修改length 
            // 大于新值
            // 如果更改的索引小于收集的索引，也要触发effect
            if (key === 'length' || key > newValue) {
                add(dep)
            }
        })
    } else {
        // 可能是对象
        if (key !== undefined) {
            add(depsMap.get(key))
        }
        // 修改数组中的某一索引
        switch(type) { //添加索引触发长度更新
            case 'add':
                if (Array.isArray(target) && parseInt(key) + ''===key){
                    add(depsMap.get('length'))
                }
        }
    }

    console.log(effects)
    effects.forEach((effect)=>{
        if (effect.options.scheduler) {
            effect.options.scheduler()
        } else {
            effect()
        }
    })
}
